#include <iostream>
#include <string>
#include <list>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::list;
using std::unique_ptr;

class Observer
{
public:
    virtual void update(int x) = 0;
    virtual ~Observer(){  }
};

class ConcreteObserver1
: public Observer
{
public:
    ConcreteObserver1(const string &name)
    : _name(name)
    {

    }

    virtual void update(int x) override
    {
        cout << ">>ConcreteObserver1  name " << _name 
             << ", value " << x << endl; 
    }
private:
    string _name;
};

class ConcreteObserver2
: public Observer
{
public:
    ConcreteObserver2(const string &name)
    : _name(name)
    {

    }

    virtual void update(int x) override
    {
        cout << ">>ConcreteObserver2  name " << _name 
             << ", value " << x << endl; 
    }
private:
    string _name;
};

class Subject
{
public:
    //添加观察者
    virtual void attach(Observer *pobserver) = 0;
    //移除观察者
    virtual void detach(Observer *pobserver) = 0;
    //发通知
    virtual void notify() = 0;
    virtual ~Subject() {  }
};

class ConcreteSubject
: public Subject
{
public:
    virtual void attach(Observer *pobserver) override
    {
        if(pobserver)
        {
            _obtList.push_back(pobserver);
        }
    }

    //移除观察者
    virtual void detach(Observer *pobserver) override
    {
        if(pobserver)
        {
            _obtList.remove(pobserver);
        }
    }

    //发通知
    virtual void notify() override
    {
        for(auto &ob : _obtList)
        {
            ob->update(_status);//体现多态
        }
    }

    void setStatus(int status)
    {
        _status = status;
    }

    int getStatus()
    {
        return _status;
    }

    ~ConcreteSubject() {  }
private:
    list<Observer *> _obtList;
    int _status;
};

void test()
{
    unique_ptr<Observer> po1(new ConcreteObserver1("xiaohong"));
    unique_ptr<Observer> po2(new ConcreteObserver2("wangdao"));
    unique_ptr<ConcreteSubject> psub(new ConcreteSubject());

    //将两个观察者添加到主题中
    psub->attach(po1.get());
    psub->attach(po2.get());
    //当主题的状态发生改变之后，所有观察者的状态都会更新
    psub->setStatus(10);
    psub->notify();

    //某个观察者不想观察主题
    cout << endl << endl;
    psub->detach(po2.get());
    //当主题的状态再次发生变更之后，观察者2的状态就不会更新
    //（收不到通知）
    psub->setStatus(20);
    psub->notify();
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

